﻿using DevExpress.Utils.Menu;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraEditors.Repository;
using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraGrid.Menu;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Views.Grid.ViewInfo;
using DevExpress.XtraPrinting;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

namespace Ersur
{
    public class GridManager
    {
        public GridUtility gridUtility;
        private GridMenu gridMenu;
        public GridMenu GridMenu
        {
            get { return gridMenu; }
            set { gridMenu = value; }
        }
        private GridView gridView;

        public static Dictionary<int, GridManager> Items = new Dictionary<int, GridManager>();

        public GridManager(GridView gridView)
        {
            this.GridView = gridView;

            this.gridMenu = new GridMenu(this);

            this.gridUtility = new GridUtility(this);

            Grid.ProcessGridKey += new KeyEventHandler(Grid_ProcessGridKey);
            Grid.KeyPress += new KeyPressEventHandler(Grid_KeyPress);
            GridView.PopupMenuShowing += new PopupMenuShowingEventHandler(GridView_PopupMenuShowing);
            GridView.RowCellStyle += new RowCellStyleEventHandler(gridView_RowCellStyle);
            GridView.InvalidValueException += new InvalidValueExceptionEventHandler(GridView_InvalidValueException);
        }

        void GridView_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e)
        {
            if (e.MenuType == GridMenuType.Row)
            {
                e.Menu = gridMenu.RowMenu;
            }
        }

        void GridView_InvalidValueException(object sender, InvalidValueExceptionEventArgs e)
        {
            if (!this.gridUtility.ShowValidationException)
            {
                throw e.Exception;
            }
        }

        void Grid_KeyPress(object sender, KeyPressEventArgs e)
        {

            if (e.KeyChar == 22 || e.KeyChar == 7)
            {
                e.Handled = true;
            }
        }

        public GridView GridView
        {
            get { return gridView; }
            set { gridView = value; }
        }

        public GridControl Grid
        {
            get { return gridView.GridControl; }

        }

        public static GridManager GetManager(GridView gridView)
        {
            GridManager gridManager = null;

            bool exists = Items.TryGetValue(gridView.GetHashCode(), out gridManager);

            if (!exists)
            {
                GridManager gm = new GridManager(gridView);
                GridManager.Items.Add(gridView.GetHashCode(), gm);
                Items.TryGetValue(gridView.GetHashCode(), out gridManager);
            }

            return gridManager;
        }

        private void gridView_RowCellStyle(object sender, RowCellStyleEventArgs e)
        {
            if (e.RowHandle == DevExpress.XtraGrid.GridControl.AutoFilterRowHandle)
            {
                e.Appearance.BackColor = System.Drawing.Color.LightGoldenrodYellow;
            }
        }

        private void Grid_ProcessGridKey(object sender, KeyEventArgs e)
        {
            GridControl gc = (GridControl)sender;
            int FocusedRowHandle = (gc.MainView as ColumnView).FocusedRowHandle;
            GridColumn focusedColumn = (gc.MainView as ColumnView).FocusedColumn;

            e.Handled = true;

            if ((e.KeyData == (Keys.Control | Keys.V)))
            {
                e.Handled = gridUtility.PasteFromClipboard();
            }
            else if ((e.KeyData == Keys.Delete))
            {
                if (GridView.ActiveEditor == null || !GridView.ActiveEditor.IsEditorActive)
                    gridUtility.DeleteValue();
                else
                    e.Handled = false;
            }
            else
            {
                e.Handled = false;
            }
        }
    }

    public class GridUtility
    {
        #region Members
        private GridView gridView;
        bool showValidationException = true;

        public GridView GridView
        {
            get { return gridView; }
            set { gridView = value; }
        }

        public bool ShowValidationException
        {
            get { return showValidationException; }
            set { showValidationException = value; }
        }
        #endregion

        #region Constructors
        public GridUtility(GridView view)
        {
            this.gridView = view;
        }

        public GridUtility(GridManager gridManager)
        {
            this.gridView = gridManager.GridView;
        }

        #endregion

        private void SetFocusedGridValue(int rowHandle, GridColumn column, object val)
        {
            try
            {
                val = val.ToString().Trim();
                if (val.ToString() == string.Empty)
                {
                    GridView.FocusedRowHandle = rowHandle;                    
                    GridView.SetRowCellValue(rowHandle, column, DBNull.Value);
                    return;
                }

                #region SetValueByControlType
                if (column.ColumnEdit is RepositoryItemGridLookUpEdit ||
                    column.ColumnEdit is RepositoryItemSearchLookUpEdit)
                {
                    RepositoryItemGridLookUpEditBase ri = column.ColumnEdit as RepositoryItemGridLookUpEditBase;

                    System.Data.DataView dt;
                    if (ri.DataSource.GetType() == typeof(System.Data.DataView))
                        dt = (System.Data.DataView)ri.DataSource;
                    else
                        dt = ((System.Data.DataTable)ri.DataSource).DefaultView;

                    System.Data.DataRow[] dr = dt.ToTable().Select(ri.DisplayMember + "='" + val + "'");
                    if (dr != null && dr.Length > 0)
                    {
                        val = dr[0][ri.ValueMember];
                        GridView.FocusedRowHandle = rowHandle;     
                        GridView.SetRowCellValue(rowHandle, column, val);
                    }
                }
                else
                {
                    ShowValidationException = false;
                    try
                    {
                        //Yapıştırırken sorun olursa hata mesajı göstermesini sağlamak için   
                        GridView.FocusedRowHandle = rowHandle;     
                        GridView.SetRowCellValue(rowHandle, column, val);
                    }
                    catch (Exception)
                    {
                    }
                    ShowValidationException = true;
                }
                #endregion
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void Copy()
        {
            //GridView.OptionsBehavior.CopyToClipboardWithColumnHeaders
            bool val = GridView.OptionsBehavior.CopyToClipboardWithColumnHeaders;
            GridView.OptionsBehavior.CopyToClipboardWithColumnHeaders = false;
            GridView.CopyToClipboard();
            GridView.OptionsBehavior.CopyToClipboardWithColumnHeaders = val;


        }

        public void CopyWithHeaders()
        {
            bool val = GridView.OptionsBehavior.CopyToClipboardWithColumnHeaders;
            GridView.OptionsBehavior.CopyToClipboardWithColumnHeaders = true;
            GridView.CopyToClipboard();
            GridView.OptionsBehavior.CopyToClipboardWithColumnHeaders = val;
        }

        public void SelectAll()
        {
            GridView.SelectAll();
        }

        public void DeleteValue()
        {
            GridCell[] cells = GridView.GetSelectedCells();
            if (cells.Length > 0)
                foreach (GridCell cell in cells)
                {
                    if (!IsReadOnly(cell.Column))                        
                        GridView.SetRowCellValue(cell.RowHandle, cell.Column, DBNull.Value);
                }
            //GridView.SetFocusedValue(null);
        }

        private bool IsNewItemRowFocused
        {
            get
            {
                return GridView.IsNewItemRow(GridView.FocusedRowHandle);
            }
        }

        public bool PasteFromClipboard()
        {
            if (IsReadOnly(GridView))
                return false;

            if (GridView.IsFilterRow(GridView.FocusedRowHandle))
                return false;

            if (GridView.IsEditing)
                return false;

            IDataObject kopyalananVeri = Clipboard.GetDataObject();

            //Kopyalanan içerik text değil
            if (!kopyalananVeri.GetDataPresent(DataFormats.Text))
                return false;

            //Trim yapılmamalı, belki boş hücre kopyalanmıştır           
            string Kaynak = ((string)kopyalananVeri.GetData(DataFormats.Text)).Replace(" mt.", "").Replace("'", "’");
            if (Kaynak == String.Empty)
                return false;

            int KopyalananSatirSayisi = -1;
            int KopyalananSutunSayisi = -1;

            //RemoveEmptyEntries 'in sakıncası yok, zira boş satırlar \r olarak geliyor.
            string[] KopyalananSatirlar = Kaynak.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
            KopyalananSatirSayisi = KopyalananSatirlar.Length;
            KopyalananSutunSayisi = KopyalananSatirlar[0].Split('\t').Length;

            bool KaynakTekHucreMi = (KopyalananSutunSayisi == 1 && KopyalananSatirSayisi == 1);

            GridCell[] HedefHucreler = GridView.GetSelectedCells();
            //Hedefin tek hücre olması ya tek hücre seçilmiş olması ya de NewItemRow'da focused olması anlamına gelir.
            //NewItemRowFocused ise selectedCells 0 geliyor.
            bool HedefTekHucreMi = HedefHucreler.Length == 1 || IsNewItemRowFocused;


            int ilkSatir = GridView.FocusedRowHandle;
            if (IsNewItemRowFocused)
                ilkSatir = GridView.RowCount - 1;

            int ilkSutun = GridView.FocusedColumn.VisibleIndex;

            GridColumn sonSutun = GridView.VisibleColumns[GridView.VisibleColumns.Count - 1];
            if (!(ilkSutun + KopyalananSutunSayisi > GridView.VisibleColumns.Count - 1))
                sonSutun = GridView.VisibleColumns[ilkSutun + KopyalananSutunSayisi - 1];

            try
            {
                #region Tek hücre kopyalandı, bütün seçili hücrelere yapıştır
                if (KaynakTekHucreMi)
                {
                    if (IsNewItemRowFocused)
                    {
                        GridView.AddNewRow();
                        //Her eklenen kaydın geçerli olabilmesi için update edilmesi gerekiyor.
                        GridView.UpdateCurrentRow();
                        SetFocusedGridValue(ilkSatir, GridView.VisibleColumns[ilkSutun], Kaynak);
                    }
                    else
                    {
                        foreach (GridCell cell in GridView.GetSelectedCells())
                        {
                            if (!IsReadOnly(cell.Column))
                                SetFocusedGridValue(cell.RowHandle, cell.Column, Kaynak);
                        }
                    }
                }
                #endregion
                else
                {
                    #region Gerekli miktarda satır ekle
                    int AsagidaKalanSatirSayisi = 0;
                    //NewItemRow da aşağıda hiç satır yok demektir (=0). NewItemRow da odaklanılmamışsa aşağıdaki satırlar hesaplanır;
                    if (!IsNewItemRowFocused)
                        AsagidaKalanSatirSayisi = GridView.RowCount - GridView.FocusedRowHandle -
                            (GridView.OptionsView.NewItemRowPosition != NewItemRowPosition.None ? 1 : 0);   //FIX: OA

                    if (KopyalananSatirSayisi > AsagidaKalanSatirSayisi)
                    {
                        int EklenmesiGerekenSatirSayisi = KopyalananSatirSayisi - AsagidaKalanSatirSayisi;

                        GridView.CloseEditor();
                        GridView.UpdateCurrentRow();

                        for (int i = 0; i < EklenmesiGerekenSatirSayisi; i++)
                        {
                            //Focused cell değişiyor
                            GridView.AddNewRow();
                            //Her eklenen kaydın geçerli olabilmesi için update edilmesi gerekiyor.
                            GridView.UpdateCurrentRow();
                        }
                    }
                    #endregion

                    for (int satirIndex = 0; satirIndex < KopyalananSatirSayisi; satirIndex++)
                    {
                        string satir = KopyalananSatirlar[satirIndex];

                        string[] hucreler = satir.Split('\t');

                        for (int sutunIndex = 0; sutunIndex < KopyalananSutunSayisi; sutunIndex++)
                        {
                            string deger = hucreler[sutunIndex];
                            int SiradakiColumnIndex = ilkSutun + sutunIndex;
                            if (SiradakiColumnIndex > GridView.VisibleColumns.Count - 1)
                                break;

                            int SiradakiRowIndex = ilkSatir + satirIndex;

                            if (!IsReadOnly(GridView.VisibleColumns[SiradakiColumnIndex]))
                                SetFocusedGridValue(SiradakiRowIndex, GridView.VisibleColumns[SiradakiColumnIndex], deger);
                        }
                    }
                }

                //Yapıştırılan alanı seç                
                if (!KaynakTekHucreMi)
                {
                    GridView.ClearSelection();
                    GridView.SelectCells(ilkSatir, GridView.VisibleColumns[ilkSutun], ilkSatir + KopyalananSatirSayisi - 1, sonSutun);
                }
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        //If the ReadOnly property is set to true, the cell values of columns cannot be modified by end-users. In this case cell editors can be invoked but end users can only select and copy an editor's content. 
        //This option is not in effect if the column's AllowEdit or the View's ColumnView.Editable option is disabled.
        //That is, if ReadOnly=False, an end-user can activate the in-place editor for copying its value to the clipboard, but cannot modify the value. If AllowEdit=False, the in-place editor cannot be open either.

        public static bool IsReadOnly(GridColumn col)
        {
            return col.View.OptionsBehavior.ReadOnly || !col.OptionsColumn.AllowEdit;
        }

        public static bool IsReadOnly(GridView GridView)
        {
            return GridView.OptionsBehavior.ReadOnly;
        }
    }

    public class GridMenu
    {
        #region Members
        private GridManager gridManager;

        private GridViewMenu customMenu;
        private List<EventHandler> customEvents = new List<EventHandler>();

        private DXSubMenuItem miDuzenle = new DXSubMenuItem("Edit");

        public GridViewMenu RowMenu;


        public GridManager GridManager
        {
            get { return gridManager; }
            set { gridManager = value; }
        }

        public GridView GridView
        {
            get { return GridManager.GridView; }
        }

        public GridUtility Utility
        {
            get { return GridManager.gridUtility; }

        }

        #endregion

        #region Constructor
        public GridMenu(GridManager gridManager)
        {
            GridManager = gridManager;

            customMenu = new GridViewMenu(this.GridView);
            miDuzenle = new DXSubMenuItem("Edit");

            CreateRowMenu();

        }
        #endregion

        public void CreateRowMenu()
        {
            RowMenu = new GridViewMenu(this.GridView);
            miDuzenle = new DXSubMenuItem("Edit");
            if (customMenu.Items.Count > 0)
            {
                for (int i = 0; i < customMenu.Items.Count; i++)
                {
                    DXMenuItem mi = customMenu.Items[i];
                    mi.Click -= customEvents[i];
                    mi.Click += customEvents[i];
                    RowMenu.Items.Add(mi);
                }

                int index = RowMenu.Items.Add(miDuzenle);
                RowMenu.Items[index].BeginGroup = true;
            }
            AddStandartMenuItems();
        }

        public void AddMenu(string caption, EventHandler click,bool beginGroup = false)
        {
            DXMenuItem di = new DXMenuItem(caption);
            customEvents.Add(click);
            customMenu.Items.Add(di);

            if (beginGroup)
                di.BeginGroup = true;

            CreateRowMenu();
        }
        
        private void addToMenu(DXMenuItem menuItem)
        {
            if (customMenu.Items.Count > 0)
            {
                miDuzenle.Items.Add(menuItem);
            }
            else
            {
                RowMenu.Items.Add(menuItem);
            }

        }

        private void AddStandartMenuItems()
        {

            DXMenuItem menuItem;
            menuItem = new DXMenuItem("Copy", new EventHandler(copy), Properties.Resources.CopyMenuItem);
            menuItem.Shortcut = Shortcut.CtrlC;
            addToMenu(menuItem);

            menuItem = new DXMenuItem("Copy with headers", new EventHandler(copyWithHeaders)/*, Properties.Resources.TableHS*/);
            addToMenu(menuItem);

            menuItem = new DXMenuItem("Paste", new EventHandler(paste), Properties.Resources.PasteMenuItem);
            menuItem.Shortcut = Shortcut.CtrlV;
            addToMenu(menuItem);
        }

        #region Menu Item Event Handlers
        private void selectAll(object sender, EventArgs e)
        {
            Utility.SelectAll();
        }

        private void copy(object sender, EventArgs e)
        {
            Utility.Copy();
        }

        public void copyWithHeaders(object sender, EventArgs e)
        {
            Utility.CopyWithHeaders();
        }

        private void paste(object sender, EventArgs e)
        {
            Utility.PasteFromClipboard();
        }

        private void delete(object sender, EventArgs e)
        {
            Utility.DeleteValue();
        }

        #endregion
    }
}